const stream = require('stream');
const Transform = stream.Transform;

/**
 * Escapes dots in the beginning of lines. Ends the stream with <CR><LF>.<CR><LF>
 * Also makes sure that only <CR><LF> sequences are used for linebreaks
 *
 * @param {Object} options Stream options
 */
//保证数据流的格式正确
class DataStream extends Transform {
  constructor(options) {
    super(options);
    // init Transform
    this.options = options || {};
    this._curLine = '';

    this.inByteCount = 0;
    this.outByteCount = 0;
    this.lastByte = false;
  }

  /**
   * Escapes dots
   */
  _transform(chunk, encoding, done) {
    let chunks = [];
    let chunklen = 0;
    let i,
      len,
      lastPos = 0;
    let buf;

    if (!chunk || !chunk.length) {
      return done();
    }

    if (typeof chunk === 'string') {
      chunk = Buffer.from(chunk);
    }

    this.inByteCount += chunk.length;

    for (i = 0, len = chunk.length; i < len; i++) {
      if (chunk[i] === 0x2e) {
        // .
        if ((i && chunk[i - 1] === 0x0a) || (!i && (!this.lastByte || this.lastByte === 0x0a))) {
          buf = chunk.slice(lastPos, i + 1);
          chunks.push(buf);
          chunks.push(Buffer.from('.'));
          chunklen += buf.length + 1;
          lastPos = i + 1;
        }
      } else if (chunk[i] === 0x0a) {
        // .
        if ((i && chunk[i - 1] !== 0x0d) || (!i && this.lastByte !== 0x0d)) {
          if (i > lastPos) {
            buf = chunk.slice(lastPos, i);
            chunks.push(buf);
            chunklen += buf.length + 2;
          } else {
            chunklen += 2;
          }
          chunks.push(Buffer.from('\r\n'));
          lastPos = i + 1;
        }
      }
    }

    if (chunklen) {
      // add last piece
      if (lastPos < chunk.length) {
        buf = chunk.slice(lastPos);
        chunks.push(buf);
        chunklen += buf.length;
      }

      this.outByteCount += chunklen;
      this.push(Buffer.concat(chunks, chunklen));
    } else {
      this.outByteCount += chunk.length;
      this.push(chunk);
    }

    this.lastByte = chunk[chunk.length - 1];
    done();
  }

  /**
   * Finalizes the stream with a dot on a single line
   */
  _flush(done) {
    let buf;
    if (this.lastByte === 0x0a) {
      buf = Buffer.from('.\r\n');
    } else if (this.lastByte === 0x0d) {
      buf = Buffer.from('\n.\r\n');
    } else {
      buf = Buffer.from('\r\n.\r\n');
    }
    this.outByteCount += buf.length;
    this.push(buf);
    done();
  }
}

module.exports = DataStream;
